/*
 * Copyright 2018 the original author or authors.
 *
 * you can use the file or import project.but Do not take legal responsibility.
 * Only for learning communication.
 *
 * Java compiled version 1.8 or higher
 *
 *
 *
 *
 */

package org.liang.javasource.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.liang.javasource.bean.BeanAttrsInfo;
import org.liang.javasource.bean.BeanInfo;
import org.liang.javasource.config.ClassConfig;

/**
 * 读取excel接口文档，记录javabean的类信息
 * 
 * @author houliang
 * @date 2018年3月5日
 */
public abstract class CreateExampleExcel {
	private static ClassConfig CONFIG_G = null;// 全局配置信息
	private static boolean isReadRow = false;// 是否需要读取的行

	public static List<BeanInfo> readExcelData(ClassConfig config) {

		CONFIG_G = config;
		String excelPath = config.filePath;
		Integer[] sheets = config.sheets;
		Workbook wb = getWorkbook(excelPath);
		if (wb == null) {
			return null;
		}
		// 初始化读取的sheets
		int sheetNum = wb.getNumberOfSheets();
		if (sheets == null) {
			sheets = new Integer[sheetNum];
			for (int i = 0; i < sheetNum; i++) {
				sheets[i] = i;
			}
		}
		// 生成javaCode对象
		List<BeanInfo> list = new ArrayList<BeanInfo>();
		for (int i = 0; i < sheets.length; i++) {
			int n = sheets[i];
			if (n > sheetNum) {
				continue;
			}
			Sheet sheet = wb.getSheetAt(n); // 获取第一个sheet表
			String sheetName = sheet.getSheetName();
			System.out.println("sheetName：" + sheetName);
			List<BeanInfo> listTemp = readSheet(sheet);
			list.addAll(listTemp);
		}

		try {
			wb.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return list;
	}

	private static List<BeanInfo> readSheet(Sheet sheet) {
		List<BeanInfo> list = new ArrayList<BeanInfo>();
		List<BeanAttrsInfo> attrList = new ArrayList<BeanAttrsInfo>();// 属性
		Set<String> pgs = new HashSet<String>();// 导入包
		BeanInfo beanInfo = new BeanInfo();// javaBean对象
		int lastNum = sheet.getLastRowNum();

		for (int i = 0; i <= lastNum; i++) {
			Row rowData = sheet.getRow(i);// 读取行

			try {
				if (rowData == null) {
					continue;
				}
				String startFlag = isStartFlag(rowData);

				if (isReadRow && "start".equals(startFlag)) {

					boolean isOverride = false;// 是否覆盖javaCode，默认不覆盖

					Object cell9 = getCellValue(rowData.getCell(9));
					if (cell9 != null) {
						isOverride = (Boolean) cell9;
					}

					Object cell11 = getCellValue(rowData.getCell(11));
					if (cell11 != null) {
						CONFIG_G.packageName = cell11.toString();
					}

					String className = getCellValue(rowData.getCell(0))
							.toString() + CONFIG_G.classSuffix;
					String classComment = getCellValue(rowData.getCell(1))
							.toString();
					beanInfo = new BeanInfo();
					beanInfo.setClassName(className);
					beanInfo.setClassComment(classComment);
					beanInfo.setAuthor(CONFIG_G.author);
					beanInfo.setClassPackage(CONFIG_G.packageName);

					String path = CONFIG_G.createPath;
					if (StringUtils.isBlank(path)) {
						File f = new File("");
						path = f.getAbsolutePath() + "\\src\\main\\java";
					}
					beanInfo.setClassPath(path);
					beanInfo.cover = isOverride;
					attrList.clear();
					pgs.clear();
				} else if (!isReadRow && "end".equals(startFlag)) {

					addBeanAttrs(rowData, attrList);// 读取行，并添加属性
					beanInfo.setAttrList(attrList);
					beanInfo.setImportPackage(pgs);

					dealBean(beanInfo);

					BeanInfo clone = beanInfo.clone();
					list.add(clone);
				} else if (isReadRow) {
					addBeanAttrs(rowData, attrList);// 读取行，并添加属性
				}

			} catch (Exception e) {
				System.err.println("第" + (i + 1) + "行异常，异常信息：");
				e.printStackTrace();
				throw new RuntimeException();
			}

		}

		return list;
	}

	// 添加业务逻辑，判断是否为request或者response类型的class处理
	private static void dealBean(BeanInfo beanInfo) {
		Set<String> pgs = beanInfo.getImportPackage();

		// 是否添加父类规则
		if (CONFIG_G.baseDtoRule) {

			String className = beanInfo.getClassName();

			if (className.contains("Request")) {
				beanInfo.setBaseDtoRule(true);
				beanInfo.setParentClass("BaseDTO");
				pgs.add("com.juneyaoair.horder.dto.BaseDTO");
			} else if (className.contains("Response")) {
				beanInfo.setBaseDtoRule(true);
				beanInfo.setParentClass("BaseResultDTO");
				pgs.add("com.juneyaoair.horder.dto.BaseResultDTO");
			}

			List<BeanAttrsInfo> ls = beanInfo.getAttrList().stream()
					.filter(o -> filerAttr(o.getName()))
					.collect(Collectors.toList());
			beanInfo.setAttrList(ls);

			boolean hasList = beanInfo.getAttrList().stream()
					.anyMatch(obj -> obj.getType().contains("List"));
			if (hasList) {
				beanInfo.getImportPackage().add("java.util.List");
			}

		}

	}

	/*
	 * 过滤属性
	 */
	private static boolean filerAttr(String attrName) {

		if (attrName.equalsIgnoreCase("version")) {
			return false;
		}
		if (attrName.equalsIgnoreCase("channelCode")) {
			return false;
		}
		if (attrName.equalsIgnoreCase("userNo")) {
			return false;
		}
		if (attrName.equalsIgnoreCase("resultCode")) {
			return false;
		}
		if (attrName.equalsIgnoreCase("errorInfo")) {
			return false;
		}
		return true;
	}

	private static void addBeanAttrs(Row rowData, List<BeanAttrsInfo> attrList) {
		String proName = getCellValue(rowData.getCell(0)).toString();
		String name = proName;
		if ("参数".equals(proName)) {
			return;
		}
		// 忽略
		Object obj = getCellValue(rowData.getCell(10));
		if (obj != null) {
			boolean isIg = (Boolean) obj;
			if (isIg) {
				return;
			}
		}
		// 是否首字母转换小写
		if (CONFIG_G.firstToLowercase) {
			proName = proName.substring(0, 1).toLowerCase()
					+ proName.substring(1);
		}

		String proType = getCellValue(rowData.getCell(1)).toString().trim();
		proType = transType(proType);// 类型转换，对象+Dto，数组转换List，基本类型不变

		if ("Int".equals(proType) || "Int16".equals(proType)) {
			proType = "int";
		}

		String proDesc = getCellValue(rowData.getCell(3)).toString();
		Object proDesc2 = getCellValue(rowData.getCell(4));
		String commentDesc = proDesc2 == null ? "" : proDesc2.toString()
				.replaceAll("\r\n", "").replaceAll("\r", "")
				.replaceAll("\n", "");
		boolean isConstParam = getCellValue(rowData.getCell(12)) == null ? false
				: true;
		attrList.add(new BeanAttrsInfo(name, proName, proType, proDesc,
				commentDesc, isConstParam));
	}

	private static String isStartFlag(Row rowData) {
		Object startObj = getCellValue(rowData.getCell(8));
		if (startObj == null) {
			return null;
		}
		if ("start".equals(startObj.toString())) {
			isReadRow = true;// 开始读取数据行
			return "start";
		} else if ("end".equals(startObj.toString())) {
			isReadRow = false;// 开始读取数据行
			return "end";
		}
		return null;
	}

	private static Object getCellValue(Cell cell) {
		Object object = null;
		if (cell == null) {
			return object;
		}
		switch (cell.getCellTypeEnum()) {
		case NUMERIC:
			object = cell.getNumericCellValue();
			break;
		case STRING:
			object = cell.getStringCellValue();
			break;
		case FORMULA:
			object = cell.getCellFormula();
			break;
		case BLANK:
			// object = cell.getStringCellValue();
			break;
		case BOOLEAN:
			object = cell.getBooleanCellValue();
			break;
		case ERROR:
			object = cell.getStringCellValue();
			break;
		default:
			System.out.println("wu");
			break;
		}
		return object;
	}

	private static String transType(String type) {
		if (noTransType(type)) {
			return type;
		}

		if (type.contains("List")) {
			String t = type.replace("List<", "").replace(">", "");
			if (!noTransType(t)) {
				t = "List<" + t + CONFIG_G.classSuffix + ">";
				return t;
			} else {
				return type;
			}
		}

		String t = type;
		if (type.indexOf("]") > 0) {// 数组
			t = type.replace("[", "").replace("]", "");

			// 判断对象是否需要加DTO后缀
			boolean b = noTransType(t);
			if (!b) {
				t = t + CONFIG_G.classSuffix;
			}
			// 数组是否转换为list
			if (CONFIG_G.arrToList) {
				t = "List<" + t + ">";
			} else {
				t = t + "[]";
			}
		} else {
			t = t + CONFIG_G.classSuffix;
		}
		return t;
	}

	/*
	 * 判断是否为基本类型，是返回true
	 */
	private static boolean noTransType(String type) {

		for (int i = 0; i < noTransTypes.length; i++) {
			if (noTransTypes[i].equalsIgnoreCase(type)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 * @param excelPath
	 *            相对excel下的文件和绝对路径
	 * @return
	 */
	private static Workbook getWorkbook(String excelPath) {
		Workbook wb = null;
		try {
			if (StringUtils.isBlank(excelPath)) {
				System.err.println("文件名不能为空" + excelPath);
				return wb;
			}
			File f = null;
			if (excelPath.indexOf("/") == -1 && excelPath.indexOf("\\") == -1) {
				f = new File("src/main/resources/example/" + excelPath);
			} else {
				f = new File(excelPath);
			}
			if (!f.exists()) {
				System.err.println("文件不存在" + f.getAbsolutePath());
				return wb;
			}

			InputStream is = new FileInputStream(f);// CreateExampleExcel.class.getClassLoader().getResourceAsStream("excel\\"
			// + excelPath);
			wb = WorkbookFactory.create(is);// 这种方式 Excel 2003/2007/2010 都是可以处理的
		} catch (Exception e) {
			System.out.println("读取文件出错");
			e.printStackTrace();
		}

		return wb;
	}

	private static final String[] noTransTypes = new String[] { "String",
			"int", "double", "list", "date", "boolean", "int16", "BigDecimal" };// 不需要转换类型
}
